/*
 * dim-sum操作系统 -- 处理器初始化
 *
 * Copyright (C) 2022 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __ASM_HEAD64_H
#define __ASM_HEAD64_H
#include <asm/mmu.h>
#include <asm/page.h>
/**
 * va_load_addr和va_exec_addr
 * 仅仅能在create_startup_mapping函数中使用
 * 用于计算在MMU开启之前的一些变量的地址
 */
#define va_load_addr(va) ({                    \
	virt_addr_t _tva = (va);                   \
	if (exec_start <= _tva && _tva < exec_end) \
	{                                          \
		_tva = _tva - exec_start + load_start; \
	}                                          \
	_tva;                                      \
})
#define va_exec_addr(va) ({                    \
	virt_addr_t _tva = (va);                   \
	if (load_start <= _tva && _tva < load_end) \
	{                                          \
		_tva = _tva - load_start + exec_start; \
	}                                          \
	_tva;                                      \
})

#define rev16(val)	\
	({ u16 rval; asm volatile(" rev16   %0, %1\n\t" : "=r" (rval) : \
	"r" (val) : "memory", "cc"); rval; })

#define rev32(val)	\
	({ u32 rval; asm volatile(" rev32   %0, %1\n\t" : "=r" (rval) : \
	"r" (val) : "memory", "cc"); rval; })

#define rev64(val)	\
		({ u32 d1, d2;	\
		d1 = (u32)((u64)val >> 32); d2 = (u32)val;	\
		d1 = rev32(d1); d2 = rev32(d2); (((u64)d2 << 32) | ((u64)d1)); })

#define mrs(spreg)		({		\
	u64 val;		\
	asm volatile("mrs %0," __stringify(spreg) : "=r"(val));	\
	val;			\
})

#define msr(spreg, val)				\
	asm volatile("msr " __stringify(spreg) ", %0"		\
		     : : "r" (val))

#define ubfx(dst, lsb, width)		({		\
	u64 val;		\
	asm volatile("ubfx %0, %1, #" __stringify(lsb) ",#" __stringify(width) \
	: "=r"(val) :"r"(dst));	\
	val;			\
})

#define sbfx(dst, lsb, width)		({		\
	u64 val;		\
	asm volatile("sbfx %0, %1, #" __stringify(lsb) ",#" __stringify(width) \
	: "=r"(val) :"r"(dst));	\
	val;			\
})

#define ALIGN_CACHE_LINE(a, s) (a & (~(s - 1))) 

extern u64 __idmap_text_start;
extern u64 __idmap_text_end;
extern u8 pgtbl_root_idmap[IDMAP_DIR_SIZE];
extern u8 pgtbl_root[GLOBAL_DIR_SIZE];

void start_die(void);
void __head __clean_inval_dcache_area(virt_addr_t start, 
							virt_size_t size);
u64 __head __config_cpu_mmu(void);
unsigned long _fdt_size(virt_addr_t dtb_start);
void __head create_sub_map(u64* tbl, u64 phys, u64 start, u64 end);
void create_startup_mapping(virt_addr_t load_start, virt_addr_t load_end,
							virt_addr_t exec_start, virt_addr_t dtb_start, 
							virt_addr_t va_off);

u32 __head __config_el2(u64 hyp_vectors);

#define PFN_ALIGN(x)	(((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
#define PFN_PHYS(x)	((phys_addr_t)(x) << PAGE_SHIFT)
#define PHYS_PFN(x)	((unsigned long)((x) >> PAGE_SHIFT))

#endif /* __ASM_HEAD64_H */
